var Point = require('./math/point');

var EPSILON = 0.001; // 浮点数计算默认精度，目前激光精度0.01
// TODO： 0.01 会导致填充的时候有很多空隙，改成 0.001会导致小数点第三位去掉后，出现相邻两个移动指令一样的情况


module.exports = {
  /*
   * Convert start+end angle arc to start/end points.
   * */
  arcToPoints: function (x, y, astart, aend, radius) {
    astart = astart % (Math.PI * 2);
    aend = aend % (Math.PI * 2);

    var a = new Point(), // start point
      b = new Point(); // end point

    a.x = radius * Math.cos(astart) + x
    a.y = radius * Math.sin(astart) + y

    b.x = radius * Math.cos(aend) + x
    b.y = radius * Math.sin(aend) + y

    return {
      start: a,
      end: b
    };
  }

  /*
   * Convert start/end/center point arc to start/end angle arc.
   * ex:
   * */
  , pointsToArc: function (center, start, end) {

    center = new Point(center.x, center.y);
    start = new Point(start.x, start.y);
    end = new Point(end.x, end.y);

    var astart = Math.atan2(start.y - center.y, start.x - center.x),
      aend = Math.atan2(end.y - center.y, end.x - center.x),
      radius = center.sub(start).magnitude();

    // Always assume a full circle
    // if they are the same 
    // Handling of 0,0 optimized in the usage
    if (aend === astart) {
      aend += Math.PI * 2;
    }

    return {
      start: astart
      , end: aend
      , radius: radius
    }
  }

  /*
  * Given an angle in radians, will return an equivalent angle between
  * [-pi, pi]
  * We have to work around Javascript's STUPID modulo bug: -2 % 3 is not -2,
  * it is 1. That's why we're calling modulo twice.
  * */
  , normalizeAngle: function (angle) {
    var a = angle + Math.PI;
    return (a % (2 * Math.PI) + 2 * Math.PI) % (2 * Math.PI) - Math.PI;
  }

  , sameFloat: function (a, b, epsilon, useRelativeError = true) {

    if (Math.abs(a - b) < EPSILON)
      return true;
    else 
      return false;
    // var absA = Math.abs(a)
    //   , absB = Math.abs(b)
    //   , diff = Math.abs(a - b)

    // epsilon = epsilon || EPSILON;

    // if (a == b) { // shortcut, handles infinities
    //   return true;
    // } else if (a == 0 || b == 0 || diff < Number.MIN_VALUE) {
    //   // a or b is zero or both are extremely close to it
    //   // relative error is less meaningful here
    //   return diff < (epsilon * Number.MIN_VALUE);
    // } else { // use relative error
    //   if (useRelativeError) {
    //     return diff / (absA + absB) < epsilon;
    //   } else {
    //     return diff < epsilon;
    //   }
    // }
  }
  , samePos: function (a, b) {
    return this.sameFloat(a.x, b.x)
      && this.sameFloat(a.y, b.y)
      && this.sameFloat(a.z, b.z)
      && this.sameFloat(a.a, b.a);
  }
  , squeeze: function () {
  }
  , spiral: function (divisions, r0, r1, loops, start, ccw, callback) {
    if (loops == 0 || loops == Infinity) {
      if (loops)
        debugger;
      return start;
    }

    // var divisions = 40;
    var end = Math.abs(loops) * divisions * 2;
    var delta = r1 - r0;
    var pitch = divisions / end * delta;
    var a = r0;
    var b = pitch / Math.PI;
    var stepAngle = Math.PI / divisions;
    start = start || 0;
    var x, y, t;
    var angle;

    for (var i = 1; i < end; i++) {
      angle = stepAngle * i;
      if (ccw) {
        x = (a + b * angle) * Math.sin(angle + start);
        y = (a + b * angle) * Math.cos(angle + start);
      }
      else {
        x = (a + b * angle) * Math.cos(angle + start);
        y = (a + b * angle) * Math.sin(angle + start);
      }

      t = i / end;

      var proceed = callback(x, y, t);
      if (proceed === false) {
        break;
      }
    }

    return angle + start;
  }
  , fomatFloat: function (src, pos) {   //src是要保留小数的值，pos是要保留几位小数；
    if (!pos) {
      pos = 3; // 默认保留到后三位
    }
    return Math.round(src * Math.pow(10, pos)) / Math.pow(10, pos);
  }
  , dist: function(x1, y1, x2, y2) {
    return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
  }

};
